/**
 * URL 工具函数 - TypeScript 版本
 * 提供 URL 验证、解析、提取、格式化等功能
 * 支持直接复制粘贴使用，无需额外配置
 * 每个函数都是独立的，可以单独复制使用
 */

// 类型定义
export interface UrlInfo {
  protocol: string;
  hostname: string;
  port: string;
  pathname: string;
  search: string;
  hash: string;
  origin: string;
  href: string;
  isValid: boolean;
}

export interface UrlParseResult {
  isValid: boolean;
  url?: UrlInfo;
  error?: string;
}

export interface UrlExtractResult {
  urls: string[];
  uniqueUrls: string[];
  count: number;
  uniqueCount: number;
}

export interface UrlParams {
  [key: string]: string | string[];
}

export interface UrlBuildOptions {
  protocol?: string;
  hostname?: string;
  port?: string | number;
  pathname?: string;
  search?: string | UrlParams;
  hash?: string;
}

// 常量定义
export const PROTOCOLS = {
  HTTP: 'http:',
  HTTPS: 'https:',
  FTP: 'ftp:',
  FILE: 'file:',
  WS: 'ws:',
  WSS: 'wss:'
} as const;

export const PORTS = {
  HTTP: 80,
  HTTPS: 443,
  FTP: 21,
  SSH: 22,
  SMTP: 25,
  POP3: 110,
  IMAP: 143,
  MYSQL: 3306,
  POSTGRES: 5432,
  REDIS: 6379,
  MONGODB: 27017
} as const;

/**
 * 验证 URL 是否有效
 * @param url - 要验证的 URL
 * @param options - 验证选项
 * @returns 是否有效
 */
export function isValidUrl(url: string, options: {
  protocols?: string[];
  requireProtocol?: boolean;
  allowLocalhost?: boolean;
  allowIP?: boolean;
} = {}): boolean {
  if (!url || typeof url !== 'string') {
    return false;
  }

  const {
    protocols = [PROTOCOLS.HTTP, PROTOCOLS.HTTPS],
    requireProtocol = true,
    allowLocalhost = true,
    allowIP = true
  } = options;

  try {
    const urlObj = new URL(url);
    
    // 检查协议
    if (requireProtocol && !protocols.includes(urlObj.protocol)) {
      return false;
    }

    // 检查主机名
    const hostname = urlObj.hostname;
    
    // 不允许 localhost
    if (!allowLocalhost && (hostname === 'localhost' || hostname === '127.0.0.1')) {
      return false;
    }

    // 不允许 IP 地址
    if (!allowIP && isIPAddress(hostname)) {
      return false;
    }

    return true;
  } catch {
    return false;
  }
}

/**
 * 解析 URL
 * @param url - 要解析的 URL
 * @returns 解析结果
 */
export function parseUrl(url: string): UrlParseResult {
  try {
    const urlObj = new URL(url);
    
    return {
      isValid: true,
      url: {
        protocol: urlObj.protocol,
        hostname: urlObj.hostname,
        port: urlObj.port,
        pathname: urlObj.pathname,
        search: urlObj.search,
        hash: urlObj.hash,
        origin: urlObj.origin,
        href: urlObj.href
      }
    };
  } catch (error) {
    return {
      isValid: false,
      error: error instanceof Error ? error.message : 'Invalid URL'
    };
  }
}

/**
 * 从文本中提取 URL
 * @param text - 包含 URL 的文本
 * @param options - 提取选项
 * @returns 提取结果
 */
export function extractUrls(text: string, options: {
  protocols?: string[];
  unique?: boolean;
  validate?: boolean;
} = {}): UrlExtractResult {
  if (!text || typeof text !== 'string') {
    return {
      urls: [],
      uniqueUrls: [],
      count: 0,
      uniqueCount: 0
    };
  }

  const {
    protocols = [PROTOCOLS.HTTP, PROTOCOLS.HTTPS],
    unique = true,
    validate = true
  } = options;

  // URL 正则表达式
  const urlRegex = /(https?:\/\/[^\s<>"{}|\\^`[\]]+)/gi;
  const urls = text.match(urlRegex) || [];

  let validUrls = urls;
  
  // 验证 URL
  if (validate) {
    validUrls = urls.filter(url => isValidUrl(url, { protocols }));
  }

  // 去重
  let uniqueUrls = validUrls;
  if (unique) {
    uniqueUrls = [...new Set(validUrls)];
  }

  return {
    urls: validUrls,
    uniqueUrls,
    count: validUrls.length,
    uniqueCount: uniqueUrls.length
  };
}

/**
 * 从文本中提取并去重 URL
 * @param text - 包含 URL 的文本
 * @returns 去重后的 URL 数组
 */
export function extractUniqueUrls(text: string): string[] {
  const result = extractUrls(text, { unique: true, validate: true });
  return result.uniqueUrls;
}

/**
 * 解析 URL 参数
 * @param url - 包含参数的 URL
 * @returns 参数对象
 */
export function parseParams(url: string): UrlParams {
  try {
    const urlObj = new URL(url);
    const params: UrlParams = {};
    
    urlObj.searchParams.forEach((value, key) => {
      if (params[key]) {
        // 如果已存在，转换为数组
        if (Array.isArray(params[key])) {
          (params[key] as string[]).push(value);
        } else {
          params[key] = [params[key] as string, value];
        }
      } else {
        params[key] = value;
      }
    });
    
    return params;
  } catch {
    return {};
  }
}

/**
 * 构建 URL
 * @param options - URL 构建选项
 * @returns 构建的 URL
 */
export function buildUrl(options: UrlBuildOptions): string {
  const {
    protocol = PROTOCOLS.HTTPS,
    hostname = 'localhost',
    port = '',
    pathname = '/',
    search = '',
    hash = ''
  } = options;

  let url = `${protocol}//${hostname}`;
  
  if (port) {
    url += `:${port}`;
  }
  
  if (pathname && pathname !== '/') {
    url += pathname.startsWith('/') ? pathname : `/${pathname}`;
  }
  
  if (search) {
    if (typeof search === 'string') {
      url += search.startsWith('?') ? search : `?${search}`;
    } else {
      const searchParams = new URLSearchParams();
      Object.entries(search).forEach(([key, value]) => {
        if (Array.isArray(value)) {
          value.forEach(v => searchParams.append(key, v));
        } else {
          searchParams.set(key, value);
        }
      });
      url += `?${searchParams.toString()}`;
    }
  }
  
  if (hash) {
    url += hash.startsWith('#') ? hash : `#${hash}`;
  }
  
  return url;
}

/**
 * 添加 URL 参数
 * @param url - 原始 URL
 * @param params - 要添加的参数
 * @returns 新的 URL
 */
export function addParams(url: string, params: UrlParams): string {
  try {
    const urlObj = new URL(url);
    
    Object.entries(params).forEach(([key, value]) => {
      if (Array.isArray(value)) {
        value.forEach(v => urlObj.searchParams.append(key, v));
      } else {
        urlObj.searchParams.set(key, value);
      }
    });
    
    return urlObj.toString();
  } catch {
    return url;
  }
}

/**
 * 移除 URL 参数
 * @param url - 原始 URL
 * @param paramNames - 要移除的参数名
 * @returns 新的 URL
 */
export function removeParams(url: string, paramNames: string[]): string {
  try {
    const urlObj = new URL(url);
    
    paramNames.forEach(paramName => {
      urlObj.searchParams.delete(paramName);
    });
    
    return urlObj.toString();
  } catch {
    return url;
  }
}

/**
 * 获取 URL 参数值
 * @param url - URL
 * @param paramName - 参数名
 * @returns 参数值
 */
export function getParam(url: string, paramName: string): string | null {
  try {
    const urlObj = new URL(url);
    return urlObj.searchParams.get(paramName);
  } catch {
    return null;
  }
}

/**
 * 检查是否为 IP 地址
 * @param hostname - 主机名
 * @returns 是否为 IP 地址
 */
export function isIPAddress(hostname: string): boolean {
  // IPv4 正则
  const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
  
  // IPv6 正则（简化版）
  const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/;
  
  return ipv4Regex.test(hostname) || ipv6Regex.test(hostname);
}

/**
 * 检查是否为本地 URL
 * @param url - URL
 * @returns 是否为本地 URL
 */
export function isLocalUrl(url: string): boolean {
  try {
    const urlObj = new URL(url);
    return urlObj.hostname === 'localhost' || 
           urlObj.hostname === '127.0.0.1' || 
           urlObj.hostname === '0.0.0.0' ||
           urlObj.protocol === 'file:';
  } catch {
    return false;
  }
}

/**
 * 检查是否为 HTTPS URL
 * @param url - URL
 * @returns 是否为 HTTPS
 */
export function isHttpsUrl(url: string): boolean {
  try {
    const urlObj = new URL(url);
    return urlObj.protocol === PROTOCOLS.HTTPS;
  } catch {
    return false;
  }
}

/**
 * 检查是否为 HTTP URL
 * @param url - URL
 * @returns 是否为 HTTP
 */
export function isHttpUrl(url: string): boolean {
  try {
    const urlObj = new URL(url);
    return urlObj.protocol === PROTOCOLS.HTTP;
  } catch {
    return false;
  }
}

/**
 * 获取域名
 * @param url - URL
 * @returns 域名
 */
export function getDomain(url: string): string | null {
  try {
    const urlObj = new URL(url);
    return urlObj.hostname;
  } catch {
    return null;
  }
}

/**
 * 获取协议
 * @param url - URL
 * @returns 协议
 */
export function getProtocol(url: string): string | null {
  try {
    const urlObj = new URL(url);
    return urlObj.protocol;
  } catch {
    return null;
  }
}

/**
 * 获取端口
 * @param url - URL
 * @returns 端口
 */
export function getPort(url: string): string | null {
  try {
    const urlObj = new URL(url);
    return urlObj.port || getDefaultPort(urlObj.protocol);
  } catch {
    return null;
  }
}

/**
 * 获取默认端口
 * @param protocol - 协议
 * @returns 默认端口
 */
export function getDefaultPort(protocol: string): string {
  switch (protocol) {
    case PROTOCOLS.HTTP:
      return '80';
    case PROTOCOLS.HTTPS:
      return '443';
    case PROTOCOLS.FTP:
      return '21';
    case PROTOCOLS.WS:
      return '80';
    case PROTOCOLS.WSS:
      return '443';
    default:
      return '';
  }
}

/**
 * 标准化 URL
 * @param url - 原始 URL
 * @returns 标准化后的 URL
 */
export function normalizeUrl(url: string): string {
  try {
    const urlObj = new URL(url);
    
    // 移除默认端口
    if (urlObj.port === getDefaultPort(urlObj.protocol)) {
      urlObj.port = '';
    }
    
    // 标准化路径
    urlObj.pathname = urlObj.pathname.replace(/\/+/g, '/');
    
    return urlObj.toString();
  } catch {
    return url;
  }
}

/**
 * 比较两个 URL 是否相同
 * @param url1 - 第一个 URL
 * @param url2 - 第二个 URL
 * @returns 是否相同
 */
export function isSameUrl(url1: string, url2: string): boolean {
  try {
    const urlObj1 = new URL(url1);
    const urlObj2 = new URL(url2);
    
    return urlObj1.href === urlObj2.href;
  } catch {
    return url1 === url2;
  }
}

/**
 * 检查 URL 是否包含指定域名
 * @param url - URL
 * @param domain - 域名
 * @returns 是否包含域名
 */
export function containsDomain(url: string, domain: string): boolean {
  try {
    const urlObj = new URL(url);
    return urlObj.hostname.includes(domain);
  } catch {
    return false;
  }
}

/**
 * 获取 URL 的哈希值
 * @param url - URL
 * @returns 哈希值
 */
export function getHash(url: string): string | null {
  try {
    const urlObj = new URL(url);
    return urlObj.hash;
  } catch {
    return null;
  }
}

/**
 * 设置 URL 的哈希值
 * @param url - 原始 URL
 * @param hash - 新的哈希值
 * @returns 新的 URL
 */
export function setHash(url: string, hash: string): string {
  try {
    const urlObj = new URL(url);
    urlObj.hash = hash;
    return urlObj.toString();
  } catch {
    return url;
  }
}

/**
 * 移除 URL 的哈希值
 * @param url - 原始 URL
 * @returns 新的 URL
 */
export function removeHash(url: string): string {
  try {
    const urlObj = new URL(url);
    urlObj.hash = '';
    return urlObj.toString();
  } catch {
    return url;
  }
}

/**
 * 检查 URL 是否安全（HTTPS 或本地）
 * @param url - URL
 * @returns 是否安全
 */
export function isSecureUrl(url: string): boolean {
  return isHttpsUrl(url) || isLocalUrl(url);
}

/**
 * 获取 URL 的路径部分
 * @param url - URL
 * @returns 路径
 */
export function getPath(url: string): string | null {
  try {
    const urlObj = new URL(url);
    return urlObj.pathname;
  } catch {
    return null;
  }
}

/**
 * 设置 URL 的路径
 * @param url - 原始 URL
 * @param path - 新的路径
 * @returns 新的 URL
 */
export function setPath(url: string, path: string): string {
  try {
    const urlObj = new URL(url);
    urlObj.pathname = path.startsWith('/') ? path : `/${path}`;
    return urlObj.toString();
  } catch {
    return url;
  }
}

/**
 * 检查 URL 是否为相对路径
 * @param url - URL
 * @returns 是否为相对路径
 */
export function isRelativeUrl(url: string): boolean {
  return !url.includes('://') && !url.startsWith('//');
}

/**
 * 将相对 URL 转换为绝对 URL
 * @param relativeUrl - 相对 URL
 * @param baseUrl - 基础 URL
 * @returns 绝对 URL
 */
export function toAbsoluteUrl(relativeUrl: string, baseUrl: string): string {
  try {
    return new URL(relativeUrl, baseUrl).toString();
  } catch {
    return relativeUrl;
  }
}

/**
 * 获取 URL 的查询字符串
 * @param url - URL
 * @returns 查询字符串
 */
export function getQueryString(url: string): string | null {
  try {
    const urlObj = new URL(url);
    return urlObj.search;
  } catch {
    return null;
  }
}

/**
 * 检查 URL 是否包含查询参数
 * @param url - URL
 * @returns 是否包含查询参数
 */
export function hasQueryParams(url: string): boolean {
  try {
    const urlObj = new URL(url);
    return urlObj.searchParams.size > 0;
  } catch {
    return false;
  }
}

/**
 * 获取 URL 的查询参数数量
 * @param url - URL
 * @returns 参数数量
 */
export function getQueryParamCount(url: string): number {
  try {
    const urlObj = new URL(url);
    return urlObj.searchParams.size;
  } catch {
    return 0;
  }
}

/**
 * 检查 URL 是否为空
 * @param url - URL
 * @returns 是否为空
 */
export function isEmptyUrl(url: string): boolean {
  return !url || url.trim() === '';
}

/**
 * 清理 URL（移除多余的空格和字符）
 * @param url - 原始 URL
 * @returns 清理后的 URL
 */
export function cleanUrl(url: string): string {
  if (!url) return '';
  
  return url
    .trim()
    .replace(/\s+/g, '')
    .replace(/[<>"{}|\\^`[\]]/g, '');
}

/**
 * 验证 URL 格式（严格模式）
 * @param url - 要验证的 URL
 * @returns 是否有效
 */
export function validateUrlStrict(url: string): boolean {
  if (!url || typeof url !== 'string') {
    return false;
  }

  // 基本格式检查
  const urlPattern = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)$/;
  
  if (!urlPattern.test(url)) {
    return false;
  }

  // 使用 URL 构造函数进一步验证
  try {
    new URL(url);
    return true;
  } catch {
    return false;
  }
}

/**
 * 批量验证 URL
 * @param urls - URL 数组
 * @returns 验证结果
 */
export function validateUrls(urls: string[]): {
  valid: string[];
  invalid: string[];
  validCount: number;
  invalidCount: number;
} {
  const valid: string[] = [];
  const invalid: string[] = [];

  urls.forEach(url => {
    if (isValidUrl(url)) {
      valid.push(url);
    } else {
      invalid.push(url);
    }
  });

  return {
    valid,
    invalid,
    validCount: valid.length,
    invalidCount: invalid.length
  };
}
